from django.db.models import Q
from rest_framework.parsers import MultiPartParser
from django.shortcuts import get_object_or_404, render
from django.contrib.contenttypes.models import ContentType
from django.utils import timezone
from rest_framework import viewsets, generics, status
from rest_framework.permissions import IsAuthenticatedOrReadOnly, IsAuthenticated, AllowAny
from rest_framework.views import APIView
from rest_framework.pagination import PageNumberPagination
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.exceptions import ValidationError

from ctbloge.apps.comments.models import Notification, Comment
import datetime
from .models import *
from .serializers import *


class ImageUploadView(APIView):
    parser_classes = (MultiPartParser,)
    permission_classes = [IsAuthenticated]  # 按需添加权限

    def post(self, request, *args, **kwargs):
        serializer = ImageUploadSerializer(data=request.data)
        if serializer.is_valid():
            return self.handle_uploaded_image(serializer.validated_data['image'],
                                              serializer.validated_data.get('article_type'))
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def handle_uploaded_image(self, image_file, article_type=None):
        try:
            # 生成存储路径
            upload_path = self.get_upload_path(article_type)

            # 保存文件
            filename = image_file.name
            save_path = os.path.join(upload_path, filename)

            with open(save_path, 'wb+') as destination:
                for chunk in image_file.chunks():
                    destination.write(chunk)

            # 返回访问URL
            media_url = settings.MEDIA_URL
            relative_path = os.path.relpath(save_path, settings.MEDIA_ROOT)
            normalized_path = relative_path.replace("\\", "/")
            return Response({
                "url": f"{media_url}{normalized_path}",
                "filename": filename
            }, status=status.HTTP_201_CREATED)

        except Exception as e:
            return Response({"error": str(e)},
                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)

    def get_upload_path(self, article_type):
        """动态生成存储路径"""
        base_path = 'cms/articles'  # 基础路径
        date_path = datetime.datetime.now().strftime("%Y-%m-%d")  # 日期路径

        # 根据类型细化路径
        if article_type == 'multi':
            full_path = os.path.join(base_path, date_path, 'gallery')
        else:
            full_path = os.path.join(base_path, date_path)

        # 创建目录（如果不存在）
        abs_path = os.path.join(settings.MEDIA_ROOT, full_path)
        os.makedirs(abs_path, exist_ok=True)

        return abs_path


class StandardPagination(PageNumberPagination):
    page_size = 15
    page_size_query_param = 'page_size'
    max_page_size = 100

    def get_paginated_response(self, data):
        return Response({
            'count': self.page.paginator.count,  # 总数量
            'page': self.page.number,  # 当前页码
            'page_size': self.page_size,  # 每页数量
            'total_pages': self.page.paginator.num_pages,  # 总页数
            'next': self.get_next_link(),  # 下一页链接
            'previous': self.get_previous_link(),  # 上一页链接
            'results': data  # 当前页返回的数据
        })


class ArticleViewSet(viewsets.ModelViewSet):
    # queryset = Article.objects.all().order_by('-created_date')
    queryset = Article.objects.prefetch_related('images').all()
    # serializer_class = ArticleSerializer
    pagination_class = StandardPagination
    permission_classes = [AllowAny]

    search_fields = ['title', 'content', 'author__username']
    ordering_fields = ['created_date', 'updated_date', 'view_count']

    def get_detail(self, request, pk=None):  # 获取文章详情
        article = get_object_or_404(Article, pk=pk)
        serializer = ArticleDetailSerializer(article)
        return Response(serializer.data)

    def get_serializer_class(self):
        if self.action == 'list':
            return ArticleListSerializer
        else:
            return ArticleDetailSerializer

    def perform_create(self, serializer):
        # 验证图片数量逻辑
        article_type = serializer.validated_data.get('article_type')
        images = self.request.FILES.getlist('images')

        if article_type == 'single' and not images:
            raise ValidationError("单图文章必须上传封面图")
        if article_type == 'multi' and len(images) < 2:
            raise ValidationError("多图文章至少需要两张图片")

        article = serializer.save()
        if images:
            for idx, image in enumerate(images):
                ArticleImage.objects.create(
                    article=article,
                    image=image,
                    order=idx
                )

    def get_queryset(self):
        # 获取基础查询集
        queryset = super().get_queryset()
        user = self.request.user

        # 根据登录状态构建不同查询条件
        if user.is_authenticated:
            # 登录用户：可以看到已发布文章 + 自己所有状态的文章
            queryset = queryset.filter(
                Q(status='published') |
                Q(author=user)
            )
        else:
            # 未登录用户：只能看到已发布文章
            queryset = queryset.filter(status='published')

        # 处理排序参数
        order = self.request.query_params.get('order')
        if order:
            if order == 'comments':
                queryset = queryset.order_by('-comments')
            elif order == 'views':
                queryset = queryset.order_by('-views_count')
            else:
                queryset = queryset.order_by('-publish_date')

        # 处理搜索参数
        search = self.request.query_params.get('search')
        if search:
            queryset = queryset.filter(
                Q(title__icontains=search) |
                Q(content__icontains=search) |
                Q(author__username__icontains=search)
            )

        return queryset.prefetch_related('tags', 'category').select_related('author')

    @action(detail=False, methods=['get'])  # 获取随机的8篇文章
    def get_random(self, request, pk=None):
        queryset = self.get_queryset()
        random_articles = queryset.order_by('?')[:8]
        serializer = ArticleListSerializer(random_articles, many=True)
        return Response(serializer.data)

    @action(detail=False, methods=['get'])  # 获取置顶文章
    def get_top(self, request, pk=None):
        queryset = self.get_queryset().filter(is_top=True)
        serializer = ArticleSimpleSerializer(queryset, many=True)
        return Response(serializer.data)

    @action(detail=False, methods=['get'])  # 获取推荐文章
    def get_recommended(self, request, pk=None):
        queryset = self.get_queryset().filter(is_recommended=True)[:10]
        serializer = ArticleSimpleSerializer(queryset, many=True)
        return Response(serializer.data)

    @action(detail=False, methods=['get'])  # 获取评论最多的10篇文章
    def get_most_commented(self, request, pk=None):
        queryset = self.get_queryset().order_by('-comments')[:10]
        serializer = ArticleListSerializer(queryset, many=True)
        return Response(serializer.data)

    @action(detail=False, methods=['get'])  # 获取阅读量最多的10篇文章
    def get_most_viewed(self, request, pk=None):
        queryset = self.get_queryset().order_by('-views_count')[:10]
        serializer = ArticleListSerializer(queryset, many=True)
        return Response(serializer.data)

    @action(detail=True, methods=['get'])  # 获取上一篇、下一篇文章
    def get_prev_next_article(self, request, pk=None):
        article = self.get_object()
        prev_article = Article.objects.filter(id__lt=article.id, status='published').order_by('-id').first()
        next_article = Article.objects.filter(id__gt=article.id, status='published').order_by('id').first()
        serializer = ArticlePrevNextSerializer(prev_article)
        prev_data = serializer.data if prev_article else None
        serializer = ArticlePrevNextSerializer(next_article)
        next_data = serializer.data if next_article else None
        return Response({'prev': prev_data, 'next': next_data})

    @action(detail=True, methods=['post'], permission_classes=[IsAuthenticated])  # 点赞
    def like(self, request, pk=None):
        article = get_object_or_404(Article, pk=pk)
        content_type = ContentType.objects.get_for_model(article)

        # 检查用户是否已经点赞了该文章
        like, created = Like.objects.get_or_create(
            user=request.user,
            content_type=content_type,
            object_id=article.id
        )
        if not created:
            like.delete()
            article.like_count -= 1
            article.save()
            Notification.objects.create(
                receiver=article.author,
                verb='like',
                sender=self.request.user,
                content='{} 撤回了对你的文章《{}》的点赞'.format(self.request.user.nickname, article.title)
            )
            return Response({'message': '取消点赞成功', 'like_count': article.like_count})
        else:
            article.like_count += 1
            article.save()
            # 点赞后发送通知
            Notification.objects.create(
                receiver=article.author,
                verb='like',
                sender=self.request.user,
                content='{} 给你的文章《{}》点了一个大大赞'.format(self.request.user.nickname, article.title)
            )
            return Response({'message': '点赞成功', 'like_count': article.like_count})

    @action(detail=True, methods=['get'], permission_classes=[IsAuthenticated])  # 查询用户是否已经点赞了该文章
    def check_like(self, request, pk=None):
        article = get_object_or_404(Article, pk=pk)
        content_type = ContentType.objects.get_for_model(article)
        like_count = Like.objects.filter(
            user=request.user,
            content_type=content_type,
            object_id=article.id
        )
        if like_count.exists():
            return Response({'message': '已点赞', 'isliked': True, 'like_count': article.like_count})
        else:
            return Response({'message': '未点赞', 'isliked': False, 'like_count': article.like_count})

    @action(detail=True, methods=['get'])  # 检查用户是否收藏了该文章
    def check_collect(self, request, pk=None):
        article = get_object_or_404(Article, pk=pk)
        content_type = ContentType.objects.get_for_model(article)
        collect_count = Collection.objects.filter(
            user=request.user,
            content_type=content_type,
            object_id=article.id
        )
        if collect_count.exists():
            return Response({'message': '已收藏', 'is_collected': True, 'collect_count': article.collect_count})
        else:
            return Response({'message': '未收藏', 'is_collected': False, 'collect_count': article.collect_count})

    @action(detail=True, methods=['post'], permission_classes=[IsAuthenticated])  # 收藏文章
    def collect(self, request, pk=None):
        article = get_object_or_404(Article, pk=pk)
        content_type = ContentType.objects.get_for_model(article)

        # 检查用户是否已经收藏了该文章
        collection, created = Collection.objects.get_or_create(
            user=request.user,
            content_type=content_type,
            object_id=article.id
        )
        if not created:
            collection.delete()
            article.collect_count -= 1
            article.save()
            Notification.objects.create(
                receiver=article.author,
                verb='collect',
                sender=self.request.user,
                content='{}取消了对你的文章《{}》的收藏'.format(self.request.user.nickname, article.title)
            )
            return Response({'message': '取消收藏成功', 'collect_count': article.collect_count})
        else:
            article.collect_count += 1
            article.save()
            # 收藏后发送通知
            Notification.objects.create(
                receiver=article.author,
                verb='collect',
                sender=self.request.user,
                content='{} 收藏了你的文章《{}》'.format(self.request.user.nickname, article.title)
            )
            return Response({'message': '收藏成功', 'collect_count': article.collect_count})

    @action(detail=False, methods=['get'])  # 获取文章归档信息
    def get_archive(self, request, pk=None):
        queryset = self.get_queryset().filter(status='published').order_by('-publish_date')
        serializer = ArchiveSerializer(queryset, many=True)
        return Response(serializer.data)

    # 获取当前文章的评论数量以及评论人数量
    @action(detail=True, methods=['get'])
    def get_comment_info(self, request, pk=None):
        article = self.get_object()
        comment_count = article.comments.count()
        author_count = article.comments.values('author').distinct().count()
        return Response({'comment_count': comment_count, 'author_count': author_count})

    # 获取个人文章列表,包含已发布、草稿、待审核、已驳回
    @action(detail=False, methods=['get'], permission_classes=[IsAuthenticated])
    def get_my_articles(self, request, pk=None):
        user = request.user
        articles = Article.objects.filter(author=user,
                                          status__in=['published', 'draft', 'pending', 'rejected']).order_by(
            '-created_date')
        serializer = PersonalArticleSerializer(articles, many=True)
        return Response(serializer.data)

    # 发布个人文章，将文章状态设置为已发布
    @action(detail=True, methods=['put'], permission_classes=[IsAuthenticated])
    def publish_article(self, request, pk=None):
        user = request.user
        if user.is_authenticated:
            article = self.get_object()
            if article.author == user:  # 只有作者可以发布文章
                article.status = 'pending'
                article.publish_date = timezone.now()
                article.save()
                return Response({'message': '发布提交成功，请等待审核', 'status': 'pending'})
            else:
                return Response({'message': '你没有权限发布该文章'}, status=status.HTTP_403_FORBIDDEN)
        else:
            return Response({'message': '请先登录'}, status=status.HTTP_401_UNAUTHORIZED)

    # 删除个人文章,将文章状态设置为删除
    @action(detail=True, methods=['delete'], permission_classes=[IsAuthenticated])
    def delete_article(self, request, pk=None):
        user = request.user
        if user.is_authenticated:
            article = self.get_object()
            if article.author == user:  # 只有作者可以删除文章
                article.status = 'deleted'
                article.save()
                return Response({'message': '删除成功'})
            else:
                return Response({'message': '你没有权限删除该文章'}, status=status.HTTP_403_FORBIDDEN)
        else:
            return Response({'message': '请先登录'}, status=status.HTTP_401_UNAUTHORIZED)

    # 批量删除个人文章,将文章状态设置为删除
    @action(detail=False, methods=['post'], permission_classes=[IsAuthenticated])
    def batch_delete_articles(self, request, pk=None):
        user = request.user
        if user.is_authenticated:
            ids = request.data.get('article_ids')
            articles = Article.objects.filter(id__in=ids, author=user)
            articles.update(status='deleted')
            return Response({'message': '批量删除成功'})
        else:
            return Response({'message': '请先登录'}, status=status.HTTP_401_UNAUTHORIZED)

    # 修改个人文章
    @action(detail=True, methods=['put'], permission_classes=[IsAuthenticated])
    def modify_article(self, request, pk=None):
        user = request.user
        article = self.get_object()
        # 对传递的tags、images进行处理
        new_tags = request.data.getlist('tags[]', [])  # 接收数组格式
        article.tags.clear()  # 清空原有标签

        for tag_value in new_tags:
            # 尝试作为ID处理
            if tag_value.isdigit():
                try:
                    tag = Tag.objects.get(id=int(tag_value))
                    article.tags.add(tag)
                    continue
                except Tag.DoesNotExist:
                    pass

            # 作为名称处理
            tag_name = tag_value.strip()
            if tag_name:
                tag, _ = Tag.objects.get_or_create(name=tag_name)
                article.tags.add(tag)

        new_categories = request.data.get('category')
        if new_categories:
            article.category = Category.objects.get(id=new_categories)

        # 验证图片数量逻辑
        new_type = request.data.get('article_type')
        new_image = request.data.get('image')
        new_images = self.request.FILES.getlist('images')
        if new_type == 'single':
            if new_image:
                if article.image:  # 删除旧封面图
                    article.images.all().delete()  # 删除原来的图片
                    article.image.delete()
                article.image = new_image
            else:
                raise ValidationError("单图文章必须上传封面图")

        elif new_type == 'multi':
            if new_images:
                if len(new_images) < 2:
                    raise ValidationError("多图文章至少需要两张图片")
                # 删除旧图
                article.image.delete()
                article.images.all().delete()  # 删除原来的图片
                for idx, img in enumerate(new_images):
                    ArticleImage.objects.create(article=article, image=img, order=idx)

            else:
                raise ValidationError("多图文章必须上传图片")

        # 更新文章类型
        article.article_type = new_type

        # 对文章内容进行处理
        content = request.data.get('content')
        if content:
            article.content = content
        excerpt = request.data.get('excerpt')
        if excerpt:
            article.excerpt = excerpt

        # 保存更新的文章
        article.save()  # 保存文章信息
        return Response({"message": "文章修改成功"}, status=status.HTTP_200_OK)

    # 新建个人文章
    @action(detail=False, methods=['post'], permission_classes=[IsAuthenticated])
    def create_article(self, request, pk=None):
        user = request.user
        serializer = ArticleCreateSerializer(data=request.data, context={'request': request})
        serializer.is_valid(raise_exception=True)

        validated_data = serializer.validated_data
        article_type = validated_data.get('article_type')
        new_images = request.FILES.getlist('images')  # 直接从 FILES 获取上传的文件
        article = serializer.save(author=user)

        if article_type == 'single' and not validated_data.get('image'):
            raise ValidationError({"image": "单图文章必须上传封面图"})
        elif article_type == 'multi':
            if len(new_images) < 2:
                raise ValidationError({"images": "多图文章至少需要两张图片"})
            # 创建新图片记录时使用正确字段
            for idx, img in enumerate(new_images):
                ArticleImage.objects.create(article=article, image=img, order=idx)

        # 处理标签逻辑
        for tag_value in request.data.getlist('tags[]', []):
            try:
                if tag_value.isdigit():
                    tag = Tag.objects.get(id=int(tag_value))
                else:
                    tag, _ = Tag.objects.get_or_create(name=tag_value.strip())
                article.tags.add(tag)
            except (ValueError, Tag.DoesNotExist):
                continue

        return Response(serializer.data, status=status.HTTP_201_CREATED)



class CategoryViewSet(viewsets.ModelViewSet):
    queryset = Category.objects.all()
    permission_classes = [AllowAny]

    def get_serializer_class(self):
        if self.action == 'list':
            return CategorySerializer
        else:
            return CategoryListSerializer

    @action(detail=False, methods=['get'])  # 查询所有顶级分类
    def get_top_categories(self, request, pk=None):
        categories = Category.objects.filter(parent__isnull=True)
        serializer = CategoryListSerializer(categories, many=True)
        return Response(serializer.data)

    @action(detail=False, methods=['get'])  # 获取所有二级分类
    def get_second_categories(self, request, pk=None):
        categories = Category.objects.filter(parent__isnull=False)
        serializer = CategoryListSerializer(categories, many=True)
        return Response(serializer.data)
    @action(detail=False, methods=['get'])  # 获取不同分类下的子分类，默认获取文章分类下的子分类，pk=2是文章分类的id
    def get_category_info(self, request):
        pk = request.query_params.get('pk')
        if not pk:
            pk = None
        child_categories = Category.objects.filter(parent=pk)
        serializer = CategoryListSerializer(child_categories, many=True)
        return Response(serializer.data)

    @action(detail=False, methods=['get'])  # 获取分类下的文章数量、文章标题id、url
    def get_category_article_info(self, request, pk=None):
        categories = Category.objects.all()
        serializer = CategoryArticleInfoSerializer(categories, many=True)
        return Response(serializer.data)

    @action(detail=True, methods=['get'])  # 获取分类下的所有文章,并分页
    def get_articles(self, request, pk=None):
        category = self.get_object()
        articles = Article.objects.filter(category=category, status='published').order_by('-publish_date')
        page = self.paginate_queryset(articles)
        if page is not None:
            serializer = ArticleListSerializer(page, many=True)
            return self.get_paginated_response(serializer.data)
        serializer = ArticleListSerializer(articles, many=True)
        return Response(serializer.data)


class TagViewSet(viewsets.ModelViewSet):
    queryset = Tag.objects.all()
    serializer_class = TagSerializer
    permission_classes = [AllowAny]

    def get_queryset(self):
        queryset = super().get_queryset()
        order = self.request.query_params.get('order')

        if order:  # 根据排序方式返回不同的文章列表
            if order == 'comments':
                queryset = queryset.order_by('-comments')
            elif order == 'views':
                queryset = queryset.order_by('-views_count')
            else:
                queryset = queryset.order_by('publish_date')
        return queryset

    @action(detail=False, methods=['get'])  # 获取所有标签以及对应的文章数量、文章标题id、url
    def get_tags(self, request, pk=None):
        tags = Tag.objects.all()
        serializer = TagSerializer(tags, many=True)
        return Response(serializer.data)

    # 获取随机的50个标签
    @action(detail=False, methods=['get'])
    def get_random_tags(self, request, pk=None):
        tags = Tag.objects.all().order_by('?')[:50]
        serializer = TagSerializer(tags, many=True)
        return Response(serializer.data)

    @action(detail=True, methods=['get'])  # 获取标签下的所有文章,并分页
    def get_articles(self, request, pk=None):
        tag = self.get_object()
        articles = Article.objects.filter(tags=tag, status='published').order_by('-publish_date')
        paginator = StandardPagination()  # 自定义分页器
        paginated_queryset = paginator.paginate_queryset(articles, request)
        serializer = ArticleListSerializer(paginated_queryset, many=True)
        return paginator.get_paginated_response(serializer.data)


class TopicsViewSet(viewsets.ModelViewSet):
    queryset = Topic.objects.all()
    serializer_class = TopicSerializer
    permission_classes = [AllowAny]

    @action(detail=False, methods=['get'])  # 获取所有专题以及对应的文章数量、文章标题id、url
    def get_topics(self, request, pk=None):
        topics = Topic.objects.all()
        serializer = TopicSerializer(topics, many=True)
        return Response(serializer.data)

    # 获取专题下的所有文章,并分页
    @action(detail=True, methods=['get'])
    def get_articles(self, request, pk=None):
        topic = self.get_object()
        articles = Article.objects.filter(topics=topic, status='published').order_by('-publish_date')
        page = self.paginate_queryset(articles)
        if page is not None:
            serializer = ArticleListSerializer(page, many=True)
            return self.get_paginated_response(serializer.data)
        serializer = ArticleListSerializer(articles, many=True)
        return Response(serializer.data)
